/*
 * Fichier: GenerateArticle.java
 * Crée le: 10 juillet 2007.
 * Modifié: 20 juin 2012.
 * Auteurs: Sébastien ESTIENNE.
 * SiteWeb: http://www.prog-info.org/
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package generator.developpez;



import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javaexos.business.Book;
import javaexos.business.Chapter;
import javaexos.io.XMLFileBook;
import javaexos.model.ChapterMutableModel;
import javaexos.model.ExerciseModel;



/**
 * <p>Génère un article d'un chapitre pour Developpez.</p>
 * @author Sébastien ESTIENNE.
 */
public class GenerateArticle
{
   /**
    * Le retour de ligne des chaines de caractères utilisé par le système.
    */
   public static final String LINE_BREAK = System.getProperty("line.separator");
   
   /** Les informations du chapitre. */
   private ChapterMutableModel chapter;

   /** Répertoire où se trouve le code source des exercices. */
   private String exercisesPath = null;
   
   /** Répertoire de sortie où sera produit l'article. */
   private String dvpzPath = null;
   

   /**
    * <p>Génère un article pour un chapitre donné.</p>
    * @param chapterFilepath Chemin vers le chapitre au format XML à analyser.
    * @param exercisesPath Répertoire où se trouve le code source des exercices.
    * @param dvpzPath Répertoire de sortie où l'article sera produit.
    */
   public GenerateArticle(String chapterFilepath, String exercisesPath, String dvpzPath)
   {
      // Initialisation des répertoires.
      this.exercisesPath = exercisesPath;
      this.dvpzPath = dvpzPath;
      
      // Initialisation du chapitre.
      this.chapter = new Chapter();

      // Transforme le chemin vers le chapitre en URL.
      URL url = null;
      try
      {
         url = new File(chapterFilepath).toURI().toURL();
      }
      catch(MalformedURLException e)
      {
         e.printStackTrace();
      }
      
      // Charge le chapitre.
      Book book = new XMLFileBook();
      this.chapter = book.parseChapter(url);
      
      // Génère les fichiers de l'article.
      if(this.chapter != null)
      {
         generateArticle();
      }
   }


   /**
    * <p>Génère l'article du chapitre.</p>
    */
   private void generateArticle()
   {
      // Chemin de génération des articles.
      String path = this.dvpzPath + File.separator;

      // Le chemin du fichier.
      File file = new File(path + this.chapter.getName() + ".xml");

      // Pour écrire dans le fichier.
      PrintWriter writer = null;

      // Supprime le fichier s'il existe déjà.
      if(file.exists())
      {
         file.delete();
      }

      // Ecrit l'article.
      try
      {
         // Format decimal de date.
         DecimalFormat dateFormat = new DecimalFormat("00");

         // Création du fichier.
         file.createNewFile();
         writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));

         // "Validité" de l'article.
         String validDir = null;
         if(this.chapter.isValidated())
         {
            validDir = "tutoriels/java/";
         }
         else
         {
            validDir = "encours/";
         }

         // En tête de l'article.
         writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
         writer.write("<document>\n");
         writer.write("    <!-- en-tete d'article -->\n");
         writer.write("    <entete>\n");
         writer.write("        <rubrique>4</rubrique>\n");
         writer.write("        <meta>\n");

         // Description.
         writer.write("            <description>Exercices en Java pour le chapitre "
               + this.chapter.getNumber() + " : " + this.chapter.getTitle() + "</description>\n");

         // Mots clés.
         writer.write("            <keywords>");
         List<String> keyWords = this.chapter.getKeyWords();
         for(int i = 0; i < keyWords.size() - 1; i++)
         {
            writer.write(keyWords.get(i) + ", ");
         }
         if(keyWords.size() > 0)
         {
            writer.write(keyWords.get(keyWords.size() - 1));
         }
         writer.write("</keywords>\n");
         writer.write("        </meta>\n");

         // Titre de l'article.
         writer.write("        <titre>\n");
         writer.write("            <page>" + this.chapter.getTitle() + "</page>\n");
         writer.write("            <article>Exercices en Java (");
         if(this.chapter.getNumber() < 10)
         {
            writer.write("0");
         }
         writer.write(this.chapter.getNumber() + "-" + this.chapter.getTitle() + ")</article>\n");
         writer.write("        </titre>\n");

         // Dates : création et mise à jour.
         Calendar creation = this.chapter.getCreation();
         writer.write("        <date>" + dateFormat.format(creation.get(Calendar.YEAR))
               + "-" + dateFormat.format(creation.get(Calendar.MONTH) + 1) + "-"
               + dateFormat.format(creation.get(Calendar.DAY_OF_MONTH)) + "</date>\n");
         Calendar today = Calendar.getInstance();
         writer.write("        <miseajour>"
               + today.get(Calendar.YEAR) + "-"
               + dateFormat.format(today.get(Calendar.MONTH) + 1) + "-"
               + dateFormat.format(today.get(Calendar.DAY_OF_MONTH)) + "</miseajour>\n");

         // Licence.
         writer.write("        <licauteur>Sébastien ESTIENNE</licauteur>\n");
         writer.write("        <lictype>2</lictype>\n");
         writer.write("        <licannee>" + creation.get(Calendar.YEAR) + "</licannee>\n");

         // Serveur.
         writer.write("        <serveur>Developpez</serveur>\n");
         writer.write("        <chemin>" + validDir + this.chapter.getName() + "/</chemin>\n");
         writer.write("        <urlhttp>http://sebastien-estienne.developpez.com/" + validDir
               + this.chapter.getName() + "/</urlhttp>\n");

         // Pdf.
         writer.write("        <pdf>\n");
         writer.write("            <largeurImages>75%</largeurImages>\n");
         writer.write("            <sautDePageAvantSection>0</sautDePageAvantSection>\n");
         writer.write("            <notesBasPage>FinDocument</notesBasPage>\n");
         writer.write("        </pdf>\n");
         
         writer.write("    </entete>\n");

         // Auteurs.
         writer.write("    <!-- description des auteurs -->\n");
         writer.write("    <authorDescriptions>\n");
         writer.write("        <authorDescription name=\"TheSeb\">\n");
         writer.write("            <fullname>Sébastien ESTIENNE</fullname>\n");
         writer.write("            <url>http://www.developpez.net/forums/member.php?u=35021"
               + "</url>\n");
         writer.write("            <homepage>\n");
         writer.write("                <title>Accueil</title>\n");
         writer.write("                <url>http://sebastien-estienne.developpez.com/</url>\n");
         writer.write("            </homepage>\n");
         writer.write("        </authorDescription>\n");
         writer.write("    </authorDescriptions>\n");

         // Licence.
         writer.write("    <!-- licence de reproduction affiché en bas de l'article -->\n");
         writer.write("    <licence>\n");
         writer.write("        Ce document est issu de http://www.developpez.com et reste la "
               + "propriété exclusive de son auteur.\n");
         writer.write("        La copie, modification et/ou distribution par quelque moyen que "
               + "ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.\n");
         writer.write("    </licence>\n");
         writer.write("    <!-- url où trouver le fichier inclus pour créer le cadre des renvois "
               + "en fin d'article -->\n");
         writer.write("    <reference></reference>\n");
         writer.write("    <!-- résumé très bref de l'article affiché dans le cadre bleu en tête "
               + "de page-->\n");

         // Synopsis.
         writer.write("    <synopsis>\n");
         writer.write("        <paragraph>");
         writer.write(this.chapter.getPresentation().replaceAll("\n", "\n    ") + "    <br/>\n");
         writer.write("        </paragraph>\n");
         writer.write("        <liste titre=\"Les principales notions abordées sont les "
               + "suivantes :\">\n");
         List<String> notions = this.chapter.getNotions();
         for(String notion : notions)
         {
            writer.write("        <element>" + notion + "</element>\n");
         }
         writer.write("        </liste>\n");
         writer.write("        <imgtext type=\"info\">\n");
         writer.write("            Pour faire et comprendre ces exercices, vous aurez besoin "
               + "d'un certain nombre de notions \n");
         writer.write("            sur le langage Java en rapport avec le chapitre. Pour cela, vous "
               + "pouvez consulter les tutoriels \n");
         writer.write("            Java de developpez.com à l'adresse suivante : <link "
               + "href=\"http://java.developpez.com/cours/\" \n");
         writer.write("            title=\"Cours en Java\">http://java.developpez.com"
               + "/cours/</link><br/>\n");
         writer.write("            La documentation de l'API sur le site de Sun est aussi une "
               + "mine d'or : \n");
         writer.write("            <link href=\"http://docs.oracle.com/javase/6/docs/api/\" ");
         writer.write("title=\"Doc API Java\">http://docs.oracle.com/javase/6/docs/api/</link>\n");
         writer.write("        </imgtext>\n");
         writer.write("        <paragraph><lien-forum id=\"655533\" avecnote=\"1\"/></paragraph>\n");
         writer.write("    </synopsis>\n");

         // Sommaire.
         writer.write("    <!-- article proprement dit -->\n");
         writer.write("    <!-- ATTENTION : si un document Word est lié au XML vous ne "
               + "devez -->\n");
         writer.write("    <!--           : pas modfiier manuellement le contenu "
               + "ci-dessous. -->\n");
         writer.write("    <multi-page>\n");
         List< ? extends ExerciseModel> exercises = this.chapter.getExercises();
         for(int i = 1; i <= exercises.size(); i++)
         {
            writer.write("        <page id=\"exo" + i + "\">\n");
            writer.write("            <title>Exercice " + i + "</title>\n");
            writer.write("            <link href=\"" + arabToRoman(i) + "\"/>\n");
            writer.write("        </page>\n");
         }
         writer.write("        <page id=\"remerciements\">\n");
         writer.write("            <title>Remerciements</title>\n");
         writer.write("            <link href=\"" + arabToRoman(exercises.size() + 1) + "\"/>\n");
         writer.write("        </page>\n");
         writer.write("    </multi-page>\n");

         // Exercices.
         writer.write("    <summary>\n");
         for(ExerciseModel exo : exercises)
         {
            String romanNbr = arabToRoman(exo.getNumber());
            writer.write("        <section id=\"" + romanNbr + "\">\n");
            writer.write("            <title>" + exo.getTitle() + "</title>\n");

            // Enoncé.
            writer.write("            <section id=\"" + romanNbr + "-1\">\n");
            writer.write("                <title>Énoncé</title>");
            writer.write(exo.getDeclaration().replaceAll("\n", "\n    "));
            List<String> importList = new ArrayList<String>();
            if(this.chapter.getNumber() == 1)
            {
               importList.add("                    <element><link href=\"http://docs.oracle.com/"
                     + "javase/6/docs/api/java/lang/System.html\" title=\"System\">"
                     + "java.lang.System</link> ;</element>\n");
            }
            List<String> files = exo.getFiles();
            for(int j = 0; j < files.size(); j++)
            {
               BufferedReader reader = null;
               try
               {
                  reader = new BufferedReader(new FileReader(this.exercisesPath 
                        + File.separator + files.get(j)));

                  String line = reader.readLine();
                  boolean stopImport = false;
                  while(!stopImport && line != null)
                  {
                     boolean bImport = line.trim().startsWith("import");
                     if(bImport)
                     {
                        String lineBis = line.trim().substring(6).trim();
                        bImport = bImport
                              && (lineBis.startsWith("java") || lineBis.startsWith("org"));
                     }

                     if(bImport)
                     {
                        String[] splitLine = line.split("(\\ )|(\\.)|(;)|(import)");
                        StringBuilder apiLink = new StringBuilder();
                        StringBuilder apiImport = new StringBuilder();
                        for(int k = 0; k < splitLine.length - 1; k++)
                        {
                           if(splitLine[k].compareTo("") != 0)
                           {
                              apiLink.append(splitLine[k]).append('/');
                              apiImport.append(splitLine[k]).append('.');
                           }
                        }
                        if(splitLine[splitLine.length - 1].compareTo("") != 0)
                        {
                           apiLink.append(splitLine[splitLine.length - 1]);
                           apiImport.append(splitLine[splitLine.length - 1]);
                        }
                        importList.add("                    <element><link href=\"http://"
                              + "docs.oracle.com/javase/6/docs/api/" + apiLink + ".html\" title=\""
                              + splitLine[0] + "\">" + apiImport + "</link> ;</element>\n");
                     }
                     else if(line.contains(" class "))
                     {
                        stopImport = true;
                     }
                     line = reader.readLine();
                  }
               }
               catch(FileNotFoundException e)
               {
                  System.out.println("Erreur d'ouverture du fichier: " + files.get(j));
               }
               finally
               {
                  if(reader != null)
                  {
                     reader.close();
                  }
               }
            }
            if(importList.size() > 0)
            {
               writer.write("    <liste titre=\"Classes de l'API utilisées :\">\n");
               importList.set(importList.size() - 1, 
                     importList.get(importList.size() - 1).replace(" ;", "."));
               for(String element : importList)
               {
                  writer.write(element);
               }
               writer.write("                </liste>\n");
            }
            writer.write("            </section>\n");

            // Images.
            writer.write("            <section id=\"" + romanNbr + "-2\">\n");
            writer.write("                <title>Aperçu</title>\n");
            writer.write("                <paragraph>\n");
            List<String> images = exo.getImages();
            for(String image : images)
            {
               writer.write("                    <image src=\"./images/" + image 
                     + "\" legende=\"Aperçu du résultat.\" alt=\"Image d'aperçu.\" "
                     + "align=\"center\"/>\n");
            }
            writer.write("                </paragraph>\n");
            writer.write("            </section>\n");

            // Démonstration.
            writer.write("            <section id=\"" + romanNbr + "-3\">\n");
            writer.write("                <title>Démonstration</title>\n");
            if(exo.getType() == ExerciseModel.ExoType.JWS)
            {
               writer.write("                <imgtext src=\"./images/Lancer.png\">\n");
               writer.write("                    <link href=\"http://sebastien-estienne"
                     + ".developpez.com/" + validDir + this.chapter.getName() + "/" 
                     + exo.getName() + ".jnlp\">Lancer avec Java Web Start</link>\n");
               writer.write("                </imgtext>\n");
               writer.write("                <paragraph>\n");
               writer.write("                    <br/>\n");
               writer.write("                    <u>Note</u> : javaws -viewer (accessible "
                     + "également depuis le panneau de configuration Java)\n");
               writer.write("                    permet de voir les différentes applications JWS "
                     + "en cache et de les gérer.\n");
               writer.write("                </paragraph>\n");
            }
            else if(exo.getType() == ExerciseModel.ExoType.JAR)
            {
               writer.write("                <imgtext src=\"./images/Jar.png\">\n");
               writer.write("                    <link href=\"http://sebastien-estienne"
                     + ".developpez.com/" + validDir + this.chapter.getName() + "/fichiers/" 
                     + exo.getName() + ".jar\">Télécharger le fichier " + "jar.</link>\n");
               writer.write("                </imgtext>\n");
               writer.write("                <paragraph>\n");
               writer.write("                    <u>Note:</u>Pour voir le résultat, ouvrez "
                     + "une console et tapez: java -jar " + exo.getName() + ".jar.\n");
               writer.write("                </paragraph>\n");
            }
            else if(exo.getType() == ExerciseModel.ExoType.APPLET)
            {
               writer.write("                <imgtext src=\"./images/Lancer.png\">\n");
               writer.write("                    <link href=\"http://sebastien-estienne"
                     + ".developpez.com/" + validDir + this.chapter.getName() + "/" 
                     + exo.getName() + ".php\">Lancer l'applet.</link>\n");
               writer.write("                </imgtext>\n");
            }
            writer.write("            </section>\n");

            // Solution.
            writer.write("            <section id=\"" + romanNbr + "-4\">\n");
            writer.write("                <title>Solution</title>\n");
            for(int j = 0; j < files.size(); j++)
            {
               writer.write("<code langage=\"java\" showLines=\"1\" titre=\"" + files.get(j)
                     + "\" fichier=\"http://sebastien-estienne.developpez.com/" + validDir
                     + this.chapter.getName() + "/fichiers/" + files.get(j)
                     + "\" dissimulable=\"1\"><![CDATA[\n");
               BufferedReader reader = null;
               try
               {
                  reader = new BufferedReader(new FileReader(this.exercisesPath 
                          + File.separator + files.get(j)));

                  String line = null;
                  while((line = reader.readLine()) != null)
                  {
                     writer.write(new String(line.getBytes(), "UTF-8") + "\n");
                  }
               }
               catch(FileNotFoundException e)
               {
                  System.out.println("Erreur d'ouverture du fichier: " + files.get(j));
                  e.printStackTrace();
               }
               finally
               {
                  if(reader != null)
                  {
                     reader.close();
                  }
               }
               writer.write("]]>\n");
               writer.write("</code>\n");
            }
            writer.write("            </section>\n");
            writer.write("        </section>\n\n");
         }

         // Remerciements.
         writer.write("        <section id=\"" + arabToRoman(exercises.size() + 1) + "\">\n");
         writer.write("            <title>Remerciements</title>\n");
         writer.write("            <paragraph>\n");
         if(this.chapter.getNumber() == 1)
         {
            writer.write("                Je remercie ChristopheJ et et Ioan pour leur aide "
                  + "et le support.<br/>\n");
            writer.write("                Merci à Anomaly et mathieu pour la mise en place "
                  + "des démos avec JWS.<br/>\n");
         }
         writer.write("                Je tiens à remercier ");
         List<String> contributors = this.chapter.getContributors();
         for(int i = 0; i < contributors.size() - 1; i++)
         {
            writer.write(contributors.get(i));
            if(contributors.size() >= 2 && i == contributors.size() - 2)
            {
               writer.write(" et ");
            }
            else
            {
               writer.write(", ");
            }
         }
         if(contributors.size() > 0)
         {
            writer.write(contributors.get(contributors.size() - 1));
         }
         writer.write(" pour les conseils, remarques et relectures.<br/>\n");
         writer.write("                Je remercie aussi www.developpez.com me permettant "
               + "de publier cet article et Nono40 pour ses outils.\n");
         writer.write("            </paragraph>\n");
         writer.write("        </section>\n");
         writer.write("    </summary>\n");
         writer.write("</document>\n");
      }
      catch(IOException ioe)
      {
         ioe.printStackTrace();
      }
      finally
      {
         if(writer != null)
         {
            writer.close();
         }
      }
   }


   /**
    * <p>Converti un nombre arabe en nombre romain.</p>
    * @param number Le nombre arabe à convertir.
    * @return Le nombre arabe converti en nombre romain.
    */
   public static String arabToRoman(int number)
   {
      char[] base10 = {'I', 'X', 'C', 'M'};
      char[] base5 = {'V', 'L', 'D'};

      StringBuilder romanNbr = new StringBuilder();

      int arabNbr = number;

      if(arabNbr <= 0 || arabNbr >= 4000)
      {
         throw new IllegalArgumentException("Le nombre doit être entre 0 et 4000");
      }

      for(int i = 3; i >= 0; i--)
      {
         int figure = (int) Math.floor(arabNbr / Math.pow(10, i));
         if(figure >= 1)
         {
            arabNbr = (int) (arabNbr - figure * Math.pow(10, i));
            if(figure <= 3)
            {
               for(int j = figure; j >= 1; j--)
               {
                  romanNbr.append(base10[i]);
               }
            }
            else if(figure == 9)
            {
               romanNbr.append(base10[i]).append(base10[i + 1]);
            }
            else if(figure == 4)
            {
               romanNbr.append(base10[i]).append(base5[i]);
            }
            else
            {
               romanNbr.append(base5[i]);
               for(int j = figure - 5; j >= 1; j--)
               {
                  romanNbr.append(base10[i]);
               }
            }
         }
      }

      return romanNbr.toString();
   }


   /**
    * <p>Lance l'application.</p>
    * @param args Les paramètres de la ligne de commande.
    */
   public static void main(String[] args)
   {
      if (args.length == 3)
      {
         // Chemin où se trouve le chapitre à XML à analyser.
         String chapterFilepath = args[0];

         // Répertoire où se trouve le code source des exercices du chapitre.
         String exercisesPath = args[1];
         
         // Répertoire de sortie où l'article sera produit.
         String dvpzPath = args[2];

         // Génération.
         new GenerateArticle(chapterFilepath, exercisesPath, dvpzPath);
      }

      System.exit(0);
   }
}
